﻿using Abp.Domain.Repositories;
using MyCompanyName.AbpZeroTemplate.Gantt.Dto;
using MyCompanyName.AbpZeroTemplate.Prm.Admin;
using MyCompanyName.AbpZeroTemplate.Prm.Mpp;
using MyCompanyName.AbpZeroTemplate.Prm.Project;
using MyCompanyName.AbpZeroTemplate.Request;
using MyCompanyName.AbpZeroTemplate.Request.Handler;
using MyCompanyName.AbpZeroTemplate.Response;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace MyCompanyName.AbpZeroTemplate.Gantt
{
    public class GanttAppService : AbpZeroTemplateAppServiceBase, MyCompanyName.AbpZeroTemplate.Gantt.IGanttAppService
    {
        public const string dateFormat = "yyyy-MM-dd\\THH:mm:ss";

        GanttManager gantt;
        private readonly ProjectManager _projectManager;
        private readonly IRepository<PushMessage> pushMessageRepository;
        private readonly IRepository<ChangeLog> changeLogRepository;

        private readonly OperationLogManager operationLogManager;
        private readonly MailManager _mailManager;

        public GanttAppService(GanttManager ganttManager, IRepository<PushMessage> _pushMessageRepository,
            IRepository<ChangeLog> _changeLogRepository,
            ProjectManager projectManager,
            MailManager mailManager,
            OperationLogManager _operationLogManager)
        {
            _projectManager = projectManager;
            pushMessageRepository = _pushMessageRepository;
            changeLogRepository = _changeLogRepository;
            gantt = ganttManager;
            operationLogManager = _operationLogManager;
            _mailManager = mailManager;
        }


        public void Download(int attId)
        {
            var att = gantt.getAttachment(attId);
            //  return File(att.Value, "application/octet-stream", att.Name);
        }

        //public ActionResult GetAllTasks()
        //{
        //    var gantt = new Gantt.EntityFramework.Gantt();
        //    var tasks = gantt.getAllTasks().Select(x => new // PM.Web.Models.TaskInfo
        //    {
        //        Id = x.Id,
        //        ParentId = x.parentIdRaw.GetValueOrDefault(),
        //        Title = x.Name,
        //        Describe = x.Note,
        //        Deliverydate = x.EndDate.ToString(),
        //        Progress = x.PercentDone.GetValueOrDefault(),
        //        Participants = x.Assignments.ToList().Select(q => new
        //        {
        //            Id = q.Resource.Name,
        //            Name = q.Resource.Name
        //        }),
        //        //Flags = x.Color,
        //        Subtasks = x.ChildrenRaw.Select(q => new { Id = q.Id, State = parse(q.PercentDone) })
        //    }).ToList();
        //    var res = new { records = tasks };
        //    return Json(res, JsonRequestBehavior.AllowGet);
        //}

        public void GetTask(int TaskId)
        {
            var t = gantt.getTask(TaskId);

            //return Json(new
            //{
            //    success = true,
            //    data = new
            //    {
            //        Title = t.Name,
            //        PercentDone = t.PercentDone,
            //        StartDate = t.StartDate.ToString(),
            //        EndDate = t.EndDate.ToString(),
            //        Participants = string.Join(",", t.Assignments.ToList().Select(q => q.Resource.Name)),
            //        Note = t.Note,
            //        CreateOn = DateTime.Now.ToString("yyyy-MM-dd"),
            //        CreateBy = "debug"
            //    }
            //});
        }

        //private PM.Web.Models.TaskStatus parse(int? done)
        //{
        //    if (!done.HasValue)
        //    {
        //        return PM.Web.Models.TaskStatus.未开始;
        //    }
        //    if (done.Value == 0)
        //    {
        //        return PM.Web.Models.TaskStatus.未开始;
        //    }
        //    if (done.Value == 100)
        //    {
        //        return PM.Web.Models.TaskStatus.已完成;
        //    }
        //    return PM.Web.Models.TaskStatus.进行中;
        //}

        /// <summary>
        /// Helper method to get POST request body.
        /// </summary>
        ///// <returns>POST request body.</returns>        
        private string getPostBody()
        {
            Stream req = HttpContext.Current.Request.InputStream;
            req.Seek(0, System.IO.SeekOrigin.Begin);
            return new StreamReader(req).ReadToEnd();
        }


        /// <summary>
        /// Load request handler.
        /// </summary>
        /// <returns>JSON encoded response.</returns>
        // [System.Web.Mvc.HttpGet]
        public string GetGannts([FromUri] string q, int projectId)
        {
            GanttLoadRequest loadRequest = null;
            ulong? requestId = null;
            // decode request object
            try
            {
                loadRequest = JsonConvert.DeserializeObject<GanttLoadRequest>(q);
            }
            catch (Exception)
            {
                throw new Exception("Invalid load JSON");
            }

            // get request identifier
            requestId = loadRequest.requestId;

            // initialize response object
            var loadResponse = new GanttLoadResponse(requestId);

            // if a corresponding store is requested then add it to the response object

            if (loadRequest.calendars != null) loadResponse.setCalendars(gantt.getCalendars(projectId), 1);
            if (loadRequest.assignments != null) loadResponse.setAssignments(gantt.getAssignments(projectId));
            if (loadRequest.tasks != null) loadResponse.setTasks(gantt.getTasks(projectId));
            if (loadRequest.resources != null) loadResponse.setResources(gantt.getResources(projectId));
            if (loadRequest.dependencies != null) loadResponse.setDependencies(gantt.getDependencies(projectId));

            // put current server revision to the response
            loadResponse.revision = gantt.getRevision(projectId);

            // just in case we make any changes during load request processing

            return JsonConvert.SerializeObject(loadResponse);
        }

        protected SyncStoreResponse AddModifiedRows(string table, SyncStoreResponse resp)
        {
            if (gantt.HasUpdatedRows(table))
            {
                if (resp == null) resp = new SyncStoreResponse();
                var rows = gantt.GetUpdatedRows(table);
                resp.rows = resp.rows != null ? resp.rows.Concat(rows).ToList() : rows;
            }
            if (gantt.HasRemovedRows(table))
            {
                if (resp == null) resp = new SyncStoreResponse();
                var removed = gantt.GetRemovedRows(table);
                resp.removed = resp.removed != null ? resp.removed.Concat(removed).ToList() : removed;
            }
            return resp;
        }

        /// <summary>
        /// 同步响应处理程序.
        /// </summary>
        /// <returns>JSON encoded response.</returns>
        // [System.Web.Mvc.HttpPost]
        public string Sync(int projectId)
        {
            ulong? requestId = null;
            GanttSyncRequest syncRequest = null;

            string json = getPostBody();

            // decode request object
            try
            {
                syncRequest = JsonConvert.DeserializeObject<GanttSyncRequest>(json, new Newtonsoft.Json.Converters.IsoDateTimeConverter { DateTimeFormat = dateFormat });
            }
            catch (Exception)
            {
                throw new Exception("Invalid sync JSON");
            }

            // initialize phantom to real Id maps
            gantt.InitRowsHolders();

            // get request identifier
            requestId = syncRequest.requestId;

            // initialize response object
            var syncResponse = new GanttSyncResponse(requestId);

            // Here we reject client's changes if we suspect that they are out-dated
            // considering difference between server and client revisions.
            // You can get rid of this call if you don't need such behavior.
            gantt.checkRevision(syncRequest.revision, projectId);

            // 如果相应的修改数据存储提供了我们处理它们

            // 首先让我们处理添加和更新记录

            CalendarSyncHandler calendarHandler = null;
            if (syncRequest.calendars != null)
            {
                calendarHandler = new CalendarSyncHandler(gantt, dateFormat);
                calendarHandler.ProjectId = projectId;
                syncResponse.calendars = calendarHandler.Handle(syncRequest.calendars, CalendarSyncHandler.Rows.AddedAndUpdated);
            }
            ResourceSyncHandler resourcesHandler = null;
            if (syncRequest.resources != null)
            {
                resourcesHandler = new ResourceSyncHandler(gantt);
                resourcesHandler.ProjectId = projectId;
                syncResponse.resources = resourcesHandler.Handle(syncRequest.resources, ResourceSyncHandler.Rows.AddedAndUpdated);
            }
            TaskSyncHandler taskHandler = null;
            if (syncRequest.tasks != null)
            {
                taskHandler = new TaskSyncHandler(gantt, dateFormat);
                taskHandler.ProjectId = projectId;
                syncResponse.tasks = taskHandler.Handle(syncRequest.tasks, TaskSyncHandler.Rows.AddedAndUpdated);
            }
            AssignmentSyncHandler assignmentHandler = null;
            if (syncRequest.assignments != null)
            {
                assignmentHandler = new AssignmentSyncHandler(gantt);
                assignmentHandler.ProjectId = projectId;
                syncResponse.assignments = assignmentHandler.Handle(syncRequest.assignments, AssignmentSyncHandler.Rows.AddedAndUpdated);
            }
            DependencySyncHandler dependencyHandler = null;
            if (syncRequest.dependencies != null)
            {
                dependencyHandler = new DependencySyncHandler(gantt);
                dependencyHandler.ProjectId = projectId;
                syncResponse.dependencies = dependencyHandler.Handle(syncRequest.dependencies, DependencySyncHandler.Rows.AddedAndUpdated);
            }

            // then let's process records removals

            if (syncRequest.dependencies != null)
                syncResponse.dependencies = dependencyHandler.HandleRemoved(syncRequest.dependencies, syncResponse.dependencies);

            if (syncRequest.assignments != null)
                syncResponse.assignments = assignmentHandler.HandleRemoved(syncRequest.assignments, syncResponse.assignments);

            if (syncRequest.tasks != null)
                syncResponse.tasks = taskHandler.HandleRemoved(syncRequest.tasks, syncResponse.tasks);

            if (syncRequest.resources != null)
                syncResponse.resources = resourcesHandler.HandleRemoved(syncRequest.resources, syncResponse.resources);

            if (syncRequest.calendars != null)
                syncResponse.calendars = calendarHandler.HandleRemoved(syncRequest.calendars, syncResponse.calendars);

            // we also return implicit modifications made by server
            // (implicit records updates/removals caused by data references)

            syncResponse.calendars = AddModifiedRows("calendars", syncResponse.calendars);
            syncResponse.tasks = AddModifiedRows("tasks", syncResponse.tasks);
            syncResponse.resources = AddModifiedRows("resources", syncResponse.resources);
            syncResponse.assignments = AddModifiedRows("assignments", syncResponse.assignments);
            syncResponse.dependencies = AddModifiedRows("dependencies", syncResponse.dependencies);

            // put current server revision to the response
            syncResponse.revision = gantt.getRevision(projectId);

            operationLogManager.FastCreate(projectId, "项目计划编辑", HostOperation.项目, "");


            return JsonConvert.SerializeObject(syncResponse);
        }

        private TaskStatus parse(int? done)
        {
            if (!done.HasValue)
            {
                return TaskStatus.未开始;
            }
            if (done.Value == 0)
            {
                return TaskStatus.未开始;
            }
            if (done.Value == 100)
            {
                return TaskStatus.已完成;
            }
            return TaskStatus.进行中;
        }


        public Dto.GetTaskOutPut Get(int taskId)
        {
            var outPut = new Dto.GetTaskOutPut();
            var task = gantt.getTask(taskId);
            outPut.Title = task.Name;
            outPut.Progress = task.PercentDone.GetValueOrDefault();
            outPut.Participants = string.Join(",", task.Assignments.ToList().Select(q => q.Resource.Name));
            outPut.Note = task.Note;
            outPut.CreateOn = task.CreationTime.ToString("yyyy-MM-dd");
            outPut.CreateBy = task.CreateBy;
            return outPut;
        }


        public List<Dto.GetProcessOutPut> GetProcess(int taskId)
        {
            List<Dto.GetProcessOutPut> results = new List<Dto.GetProcessOutPut>();
            var alls = gantt.getSchedules(taskId);
            foreach (var item in alls)
            {
                var outPut = new Dto.GetProcessOutPut();
                outPut.Id = item.Id;
                outPut.CreateOn = item.CreateOn.ToString("yyyy-MM-dd");
                outPut.CreateBy = item.CreateBy;
                outPut.Value = item.Value;
                outPut.Remark = item.Remark;
                results.Add(outPut);
            }
            return results;
        }



        public List<Dto.GetFileOutPut> GetFiles(int taskId)
        {
            List<Dto.GetFileOutPut> results = new List<Dto.GetFileOutPut>();
            var alls = gantt.getAttachments(taskId);
            foreach (var x in alls)
            {
                var outPut = new Dto.GetFileOutPut();
                outPut.Id = x.Id;
                outPut.CreateOn = x.CreateOn.ToString("yyyy-MM-dd");
                outPut.CreateBy = x.CreateBy;
                outPut.Name = x.Name;
                outPut.Extension = x.Extension;
                results.Add(outPut);
            }
            return results;
        }


        public void SaveProcess(CreateProcessInPut input)
        {
            gantt.saveProcess(input.Percent, input.Remark, input.TaskId);
        }



        public void SaveAttachment()
        {
            var taskId = HttpContext.Current.Request.Form["TaskId"];
            var file = HttpContext.Current.Request.Files[0];
            gantt.saveAttachment(new HttpPostedFileWrapper(file) as HttpPostedFileBase, int.Parse(taskId));
        }



        public void SetTaskPushMessage()
        {
            var taskId = int.Parse(HttpContext.Current.Request.Form["TaskId"]);
            var projectId = int.Parse(HttpContext.Current.Request.Form["ProjectId"]);
            var us = HttpContext.Current.Request.Form["Users"];
            List<int> users = us.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x)).ToList();
            pushMessageRepository.Delete(x => x.TaskId == taskId && x.ProjectId == projectId);
            foreach (var userId in users)
            {
                if (userId > 0)
                {
                    pushMessageRepository.Insert(new PushMessage()
                    {
                        TaskId = taskId,
                        ProjectId = projectId,
                        UserId = userId
                    });
                }
            }
        }


        public async Task CreateChangeLog()
        {
            var projectId = int.Parse(HttpContext.Current.Request.Form["ProjectId"]);
            var note = HttpContext.Current.Request.Form["Note"];
            await changeLogRepository.InsertAsync(new ChangeLog()
            {
                ProjectId = projectId,
                Note = note
            });
        }


        public List<GetChangeLogOutPut> GetChangeLog(int projectId)
        {
            var result = changeLogRepository.GetAll().Where(x => x.ProjectId == projectId).ToList().Select(m => new GetChangeLogOutPut()
            {
                CreateBy = UserManager.Users.Where(x => x.Id == m.CreatorUserId).SingleOrDefault().Name,
                CreateOn = m.CreationTime.ToString("yyyy-MM-dd"),
                Note = m.Note
            }).ToList();
            return result;
        }


        public void Export()
        {
            var projectId = int.Parse(HttpContext.Current.Request.Form["projectId"]);
            var projectInfo = _projectManager.projectRepository.Get(projectId);
            var tasks = gantt.getAllTasks().Where(x => x.ProjectId == projectId).ToList();
            var resource = gantt.getResources(projectId);

            MppInfo mpp = new MppInfo()
            {
                Tasks = new List<Prm.Mpp.TaskInfo>(),
                Assignments = new List<AssignmentInfo>(),
                Dependencies = new List<DependencyInfo>(),
                ProjectName = projectInfo.ProjectName,
                Resources = new List<ResourceInfo>(),
                Revision = gantt.getRevision(projectId)
            };

            foreach (var item in tasks)
            {
                var task = new Prm.Mpp.TaskInfo()
                {
                    Id = item.Guid,
                    IsMilestone = item.ManuallyScheduled,
                    Name = item.Name,
                    EndDate = item.EndDate.HasValue ? DateTime.Parse(item.EndDate.ToString()) : DateTime.Now,
                    ParentId = item.Parent != null ? item.Parent.Guid : Guid.Empty,
                    PercentDone = item.PercentDone.HasValue ? int.Parse(item.PercentDone.ToString()) : 0,
                    StartDate = item.StartDate.HasValue ? DateTime.Parse(item.StartDate.ToString()) : DateTime.Now
                };
                mpp.Tasks.Add(task);
                foreach (var ass in item.Assignments)
                {
                    var assignment = new AssignmentInfo()
                    {
                        TaskId = item.Guid,
                        PercentUnits = ass.Units,
                        ResourceId = ass.Resource.Id
                    };
                    mpp.Assignments.Add(assignment);
                }
                foreach (var dep in item.Predecessors)
                {
                    var pre = new DependencyInfo()
                    {
                        FromTaskId = dep.FromTask.Guid,
                        ToTaskId = dep.ToTask.Guid,
                        LinkType = dep.Type.HasValue ? (TaskDependencyType)dep.Type : 0
                    };
                    mpp.Dependencies.Add(pre);
                }
                foreach (var suc in item.Successors)
                {
                    var pre = new DependencyInfo()
                    {
                        FromTaskId = suc.FromTask.Guid,
                        ToTaskId = suc.ToTask.Guid,
                        LinkType = suc.Type.HasValue ? (TaskDependencyType)suc.Type : 0
                    };
                    mpp.Dependencies.Add(pre);
                }
            }
            foreach (var item in resource)
            {
                var res = new ResourceInfo()
                {
                    Id = item.Id,
                    Name = item.Name
                };
                mpp.Resources.Add(res);
            }

            var emptyPath = HttpContext.Current.Server.MapPath(@"/App/empty.mpp");


            using (Stream stream = File.Open(emptyPath, FileMode.OpenOrCreate))
            {
                using (Stream savepath = File.Open(@"d:\abc.mpp", FileMode.OpenOrCreate))
                {
                    MppHelper.Export(mpp, stream, savepath);
                }
            }
        }


        public void Import()
        {
            var file = HttpContext.Current.Request.Files[0];
            var fileBase = new HttpPostedFileWrapper(file) as HttpPostedFileBase;
            var mpp = MppHelper.Import(fileBase.InputStream);
        }

        /// <summary>
        /// 到期需要开始的计划
        /// </summary>
        public void GetMailGanteToStart()
        {
            DateTime dt = DateTime.Now.Date;
            var tasks = gantt.getAllTasks().Where(x => x.IsDeleted == false
                && x.StartDate.Value.Date == dt).ToList();

            var projectIds = tasks.Select(x => x.ProjectId).Distinct().ToList();
            System.Text.StringBuilder sb = new StringBuilder();
            foreach (var projectId in projectIds)
            {
                var p = _projectManager.projectRepository.Get(projectId);
                var _tasks = tasks.Where(x => x.ProjectId == projectId).ToList();
                sb = new StringBuilder();
                sb.Append(@"<style type='text/css'> 
                                table 
                                { 
                                border-collapse: collapse; 
                                border: none; 
                                width: 200px; 
                                } 
                                td 
                                { 
                                border: solid #000 1px; 
                                } 
                                </style> ");
                sb.Append("<table border=1>");
                sb.Append("<tr><td>计划</td></tr>");
                foreach (var item in _tasks)
                {

                    sb.Append(string.Format("<tr><td>{0}</td></tr>"
                   , item.Name));
                }
                sb.Append("</table>");
                Dictionary<string, string> dic = new Dictionary<string, string>();
                dic["将开始计划明细"] = sb.ToString();
                dic["将开始计划数"] = _tasks.Count.ToString();
                dic["项目编号"] = p.ProjectNo;
                _mailManager.CreateMailRecord(dic, MailCatelog.项目计划开始通知, projectId);
            }
        }
        /// <summary>
        /// 到期需要结束的计划
        /// </summary>
        public void GetMailGanteToEnd()
        {
            DateTime dt = DateTime.Now.Date;
            var tasks = gantt.getAllTasks().Where(x => x.IsDeleted == false
                && x.PercentDone < 100
                && x.EndDate.Value.Date == dt).ToList();

            var projectIds = tasks.Select(x => x.ProjectId).Distinct().ToList();
            System.Text.StringBuilder sb = new StringBuilder();
            foreach (var projectId in projectIds)
            {
                var p = _projectManager.projectRepository.Get(projectId);
                var _tasks = tasks.Where(x => x.ProjectId == projectId).ToList();
                sb = new StringBuilder();
                sb.Append(@"<style type='text/css'> 
                                table 
                                { 
                                border-collapse: collapse; 
                                border: none; 
                                width: 200px; 
                                } 
                                td 
                                { 
                                border: solid #000 1px; 
                                } 
                                </style> ");
                sb.Append("<table border=1>");
                sb.Append("<tr><td>计划</td></tr>");
                foreach (var item in _tasks)
                {

                    sb.Append(string.Format("<tr><td>{0}</td></tr>"
                   , item.Name));
                }
                sb.Append("</table>");
                Dictionary<string, string> dic = new Dictionary<string, string>();
                dic["应该完成计划明细"] = sb.ToString();
                dic["应该完成计划数"] = _tasks.Count.ToString();
                dic["项目编号"] = p.ProjectNo;
                _mailManager.CreateMailRecord(dic, MailCatelog.项目计划到期未完成通知, projectId);
            }
        }

    }


    public enum TaskStatus
    {
        未开始 = 0,
        进行中 = 1,
        已暂停 = 2,
        已完成 = 100,
        已归档 = 200
    }
}
